package cn.jjxx.modules.sys.security.shiro.web.filter.authc;

import cn.jjxx.core.model.AjaxJson;
import cn.jjxx.core.query.wrapper.EntityWrapper;
import cn.jjxx.core.utils.CacheUtils;
import cn.jjxx.core.utils.IpUtils;
import cn.jjxx.core.utils.PropertiesUtil;
import cn.jjxx.core.utils.StringUtils;
import cn.jjxx.modules.sys.entity.Dict;
import cn.jjxx.modules.sys.entity.Organization;
import cn.jjxx.modules.sys.security.shiro.exception.InvalidVerificationCodeException;
import cn.jjxx.modules.sys.security.shiro.exception.LoginCapherCodeException;
import cn.jjxx.modules.sys.security.shiro.exception.PwdAuthenticationException;
import cn.jjxx.modules.sys.security.shiro.exception.PwdErrorException;
import cn.jjxx.modules.sys.security.shiro.exception.RepeatAuthenticationException;
import cn.jjxx.modules.sys.security.shiro.realm.UserRealm.Principal;
import cn.jjxx.modules.sys.service.IDictService;
import cn.jjxx.modules.sys.service.IOrganizationService;
import cn.jjxx.modules.sys.utils.UserUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.beans.factory.annotation.Autowired;

import com.baomidou.mybatisplus.mapper.Wrapper;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 *
 * All rights Reserved, Designed By www.jjxxkj.cn
 * @title:  FormAuthenticationFilter.java
 * @package cn.jjxx.modules.sys.security.shiro.web.filter.authc
 * @description:   表单验证
 * @author: www.jjxxkj.cn
 * @date:   2017年6月26日 下午5:56:03
 * @version V1.0
 * @copyright: 2017 www.jjxxkj.cn Inc. All rights reserved.
 *
 */
public class FormAuthenticationFilter extends org.apache.shiro.web.filter.authc.FormAuthenticationFilter {

	@Autowired
	private IDictService dictService;
	public static final String DEFAULT_CAPTCHA_PARAM = "jcaptchaCode";
	public static final String DEFAULT_MOBILE_PARAM = "mobileLogin";
	public static final String DEFAULT_MESSAGE_ERROR_PARAM = "error";
	public static final String DEFAULT_MESSAGE_SUCCESS_PARAM = "success";
	public static final String DEFAULT_MESSAGE_NORMAL_PARAM = "normal";

	private String captchaParam = DEFAULT_CAPTCHA_PARAM;
	private String mobileLoginParam = DEFAULT_MOBILE_PARAM;
	private String messageErrorParam = DEFAULT_MESSAGE_ERROR_PARAM;
	private String messageSuccessParam = DEFAULT_MESSAGE_SUCCESS_PARAM;
	private String messageNormallParam = DEFAULT_MESSAGE_NORMAL_PARAM;

	@Autowired
	private IOrganizationService organizationService;

	protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) {
		String username = getUsername(request);
		String password = getPassword(request);
		if (password == null) {
			password = "";
		}
		username = UsernamePasswordToken.decode(username);
		boolean rememberMe = isRememberMe(request);
		String host = IpUtils.getIpAddr((HttpServletRequest) request);
		String captcha = VerifyCode(request);
		boolean mobile = isMobileLogin(request);
		return new UsernamePasswordToken(username, password.toCharArray(), rememberMe, host, captcha, mobile);
	}

	private String VerifyCode(ServletRequest request) {
		try {
			String captcha = request.getParameter("jcaptchaCode");
			//验证码
			String ID = ((HttpServletRequest) request).getSession().getId();
			Object b = CacheUtils.get("verifyCode" + ID);
			if(null!=b && !StringUtils.isEmpty(captcha)) {
				return String.valueOf(b.equals(captcha.toLowerCase())); 
			}else {
				return "false";
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return "false";
	}

	public String getCaptchaParam() {
		return captchaParam;
	}

	public void setCaptchaParam(String captchaParam) {
		this.captchaParam = captchaParam;
	}

	public void setMobileLoginParam(String mobileLoginParam) {
		this.mobileLoginParam = mobileLoginParam;
	}

	public void setMessageErrorParam(String messageErrorParam) {
		this.messageErrorParam = messageErrorParam;
	}

	public void setMessageSuccessParam(String messageSuccessParam) {
		this.messageSuccessParam = messageSuccessParam;
	}

	public void setMessageNormallParam(String messageNormallParam) {
		this.messageNormallParam = messageNormallParam;
	}

	public String getMessageErrorParam() {
		return messageErrorParam;
	}

	public String getMessageSuccessParam() {
		return messageSuccessParam;
	}

	public String getMessageNormallParam() {
		return messageNormallParam;
	}

	protected String getCaptcha(ServletRequest request) {
		return WebUtils.getCleanParam(request, getCaptchaParam());
	}

	public String getMobileLoginParam() {
		return mobileLoginParam;
	}

	protected boolean isMobileLogin(ServletRequest request) {
		return WebUtils.isTrue(request, getMobileLoginParam());
	}

	/**
	 * 登录成功之后跳转URL
	 */
	public String getSuccessUrl() {
		return super.getSuccessUrl();
	}

	@Override
	protected void issueSuccessRedirect(ServletRequest request, ServletResponse response) throws Exception {
		Principal p = UserUtils.getPrincipal();
		UserUtils.clearCache();
		if (p != null && !p.isMobileLogin()) {
			WebUtils.issueRedirect(request, response, getSuccessUrl(), null, true);
		} else {
			AjaxJson ajaxJson = new AjaxJson();
			ajaxJson.setRet(AjaxJson.RET_SUCCESS);
			ajaxJson.setMsg("登录成功!");
			ajaxJson.setData(UserUtils.getUser());

			ajaxJson.put("orgs", UserUtils.getOrgChilds(true, true));
			ajaxJson.put("mobileLogin", p.isMobileLogin());
			ajaxJson.put("JSESSIONID", p.getSessionid());
            Organization organization = organizationService.selectById(UserUtils.getUser().getOrgId());
            if (organization != null) {
                ajaxJson.put("orgType", organization.getOrgType());
            }
			StringUtils.printJson((HttpServletResponse) response, ajaxJson);
		}
	}

	/**
	 * 登录失败调用事件
	 */
	@Override
	protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request,
			ServletResponse response) {
		PropertiesUtil propertiesUtil = new PropertiesUtil("shiro.properties");
		Long freeze = Long.parseLong(StringUtils.defaultIfBlank(propertiesUtil.getString("shiro.user.password.maxRetry.freeze"), "600"));
		long freezeMinutes = freeze / 60;
		super.onLoginFailure(token, e, request, response);
		UsernamePasswordToken authcToken = (UsernamePasswordToken) token;
		String className = e.getClass().getName(), message = "";
		if (IncorrectCredentialsException.class.getName().equals(className)
				|| UnknownAccountException.class.getName().equals(className)) {
			message = "用户或密码错误, 请重试.";
		} else if (RepeatAuthenticationException.class.getName().equals(className)) {
			message = "请勿重复提交认证.";
		} else if (ExcessiveAttemptsException.class.getName().equals(className)) {
			message = "请勿重复提交认证,请" + freezeMinutes + "分钟之后登录";
		} else if (InvalidVerificationCodeException.class.getName().equals(className)) {
			message = "验证码错误,请重试.";
		}else if (LoginCapherCodeException.class.getName().equals(className)) {
			message = "验证输入错误";
		}else if (PwdErrorException.class.getName().equals(className)) {
			message = "当前帐号锁定，请联系管理员";
		} else if (LockedAccountException.class.getName().equals(className)) {
			message = "用户已被冻结,请联系管理员！";
		} else if (PwdAuthenticationException.class.getName().equals(className)) {
			message = "登录密码是弱口令,请联系管理员！";//+e.getMessage();
			Dict dict= getManager();
			if(null!=dict) {
				message +="<br>管理员:"+dict.getLabel()+" 电话:"+dict.getRemarks();
			}
		} else if (StringUtils.isNoneBlank(e.getMessage())) {
			message = e.getMessage();
		} else {
			message = "系统出现点问题，请稍后再试！";
			e.printStackTrace(); // 输出到控制台
		}
		if (!authcToken.isMobileLogin()) {
			request.setAttribute(getFailureKeyAttribute(), className);
			request.setAttribute(getMessageErrorParam(), message);
			return true;
		} else {
			// 登录失败返回false
			AjaxJson ajaxJson = new AjaxJson();
			ajaxJson.setRet(AjaxJson.RET_FAIL);
			ajaxJson.setMsg(message);
			ajaxJson.put("mobileLogin", authcToken.isMobileLogin());
			ajaxJson.put("JSESSIONID", UserUtils.getSession().getId());
			StringUtils.printJson((HttpServletResponse) response, ajaxJson);
			return false;
		}
	}

	Dict getManager() {
		Wrapper<Dict> wrapper = new EntityWrapper<Dict>();		
		wrapper.eq("value", "MANAGE");
		return dictService.selectOne(wrapper);
	}
}